iT邦幫忙

2022 iThome 鐵人賽

DAY 14
0

useId

說明

為了生成唯一的Id,React 18 後提供了一個新的 Hook => useId

const id = useId();

他的基本原理表示著,每個 id 都代表該元件在元件樹中的層級結構。

注意:useId 不建議用於當做 HTML 元素列表的 Key,列表的 Key 應該要於你傳入要渲染出畫面的資料有關。

用法

一個簡單的作法,可以使用 useId 產生一個 id,代表某個 DOM 的 Id

function Checkbox() {
  const id = useId();
  return (
    <>
      <label htmlFor={id}>Do you like React?</label>
      <input id={id} type="checkbox" name="react"/>
    </>
  );
};

如果同一元件內的多個 DOM 元素需要時,那麼我們可以先用 useId 產生完代表這個元件的 id,然後再為其加上後綴

function NameFields() {
  const id = useId();
  return (
    <div>
      <label htmlFor={id + '-firstName'}>First Name</label>
      <div>
        <input id={id + '-firstName'} type="text" />
      </div>
      <label htmlFor={id + '-lastName'}>Last Name</label>
      <div>
        <input id={id + '-lastName'} type="text" />
      </div>
    </div>
  );
}

注意:useId 的生成結果字串內會包含這個符號,用以確保此字串是唯一的,但這樣的字串結果就無法應用在 CSS Selector 或 querySelectorAll 等 API 中,必需要另外定義適合的 Selector。

useLayoutEffect

說明

它和 useEffect 的語法、使用上一模一樣。

會有以下幾點差異:

  • useLayoutEffect 在 Virtual-DOM 更新完,但在 Render 之前執行useEffect 則是在 Render 之後執行。
  • useLayoutEffect 是同步執行的,UI 會等 useLayoutEffect 要處理的任務做完才會做 Render。所以不要在 useLayoutEffect 中做需要大量計算的處理,會導致頁面卡頓。
  • useEffect 是異步執行的,UI Render 和 useEffect 不會有有要排隊依序執行的概念。

當你希望畫面不要有閃一下的情況時,可以使用 useLayoutEffect,因為他會在 Render 之前執新。

但如果在 useLayoutEffect 中有大量計算的處理,因為 UI 會等它做完才 Render,這時畫面反而會空白一陣子,造成 UX 體驗不好。

有時我們可以透過加上過場效果之類的 UX 解決方式,還是能使用 useEffect 完成處理。

範例比較與應用

  • useEffect
function EffectComponent() {
    const [count, setCount] = React.useState(0);
    
    React.useEffect(() => {
        console.log(`useEffect - count=${count}`)
        // 耗時的操作
        const pre = Date.now();
        while(Date.now() - pre < 500) {}
        
        // count為0時重新生成個隨機數
        if (count === 0) {    
            setCount(10 + Math.random() * 200);
        }
    }, [count]);
    
    return (
        <div className= 'EffectComponent' 
          onClick={() => setCount(0)}>
        <h2>EffectComponent</h2>
          <div>{count}</div>
        </div>
    );
}

useEffect 因為是 Render 之後才執行,所以會看到展示 0 的過程

  • useLayoutEffect
function LayoutEffectComponent() {
    const [count, setCount] = React.useState(0);
    
    React.useLayoutEffect(() => {
        console.log(`useLayoutEffect - count=${count}`)
        // 耗時的操作
        const pre = Date.now();
        while(Date.now() - pre < 500) {}
        
        // count為0時重新生成個隨機數
        if (count === 0) {    
            setCount(10 + Math.random() * 200);
        }
    }, [count]);
    
    return (
        <div className= 'LayoutEffectComponent' 
          onClick={() => setCount(0)}>
        <h2>LayoutEffectComponent</h2>
          <div>{count}</div>
        </div>
    );
}

  1. 沒有閃爍,當點擊 div,count 更新為0,此時頁面並不會渲染,而是等待 useLayoutEffect 內部狀態修改後,才會去更新頁面,所以頁面不會閃爍。
  2. 但是也可以發現頁面更新的比較卡頓,因為 useLayoutEffect 會阻塞瀏覽器渲染,正好本例中useLayoutEffect 的裡有個耗時操作,所以頁面更新比較卡頓。

完整執行結果:https://codepen.io/lala-lee-jobs/pen/BaxpaqG?editors=0111

Next

接下來介紹跟效能優化有關的二個 Hook - useMemouseCallback,以及一個 Higher-Order Component - React.memo,來幫助我們解決 React Render 時效能上的問題。

Reference

https://zh-hans.reactjs.org/docs/hooks-reference.html#useid

https://zh-hant.reactjs.org/docs/hooks-reference.html#uselayouteffect

https://segmentfault.com/a/1190000023396433


上一篇
Day 13 React.forwardRef (HOC)、useImperativeHandle
下一篇
Day 15 Memorized Hook - useMemo、useCallback
系列文
開始搞懂React生態系30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言